/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *	  http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 package com.googlecode.milib.display.button {
	import com.googlecode.milib.base.IMLBroadcasterListener;
	import com.googlecode.milib.base.MLBroadcastClass;
	import com.googlecode.milib.display.button.views.AbstractButtonView;
	import com.googlecode.milib.service.singleton.MouseService;
	import com.googlecode.milib.vo.MLEventInfo;

	import flash.events.Event;
	import flash.utils.getTimer;

	/**
	 * @author Marek Brun
	 */
	public class AbstractButton extends MLBroadcastClass implements IMLBroadcasterListener {
		
		public const event_EnabledChanged : String = 'EnabledChanged';
		
		public const event_Press : String = 'Press';
		
		public const event_DoublePress : String = 'DoublePress';
		
		public const event_Release : String = 'Release';
		
		public const event_ReleaseOutside : String = 'ReleaseOutside';
		
		public const event_ReleaseAll : String = 'ReleaseAll';
		
		public const event_RollOut : String = 'RollOut';
		
		public const event_RollOver : String = 'RollOver';
		
		public const event_DragOut : String = 'DragOut';
		
		public const event_DragOver : String = 'DragOver';
		
		public const event_Over : String = 'Over';
		
		public const event_Out : String = 'Out';
		
		public const event_OutAndRelease : String = 'OutAndRelease';
		
		public const event_OverOrOut : String = 'OverOrOut';
		
		//DATA:	MouseEvent
		public const event_MouseWheelWhenOver : String = 'MouseWheelWhenOver';
		
		public const event_MoveWhenDown : String = 'MoveWhenDown';
		
		public const event_MoveWhenOver : String = 'MoveWhenOver';
		
		private var isPressed : Boolean;
		private var isOver : Boolean;
		private var isEnabled : Boolean;
		private var lastPressTime : Number;
		private var isDragOver : Boolean;		
		private var views:Array;		
		protected var ms:MouseService;
		private var isFreezeViews:Boolean;

		public function AbstractButton() {
			isOver=false;
			isPressed=false;
			isEnabled=true;
			views=[];
			ms=MouseService.getInstance();
		}
		
		/*abstract*/ protected function doIsEnabled():void {}
		
		protected function updateViewers():void {
			if(isFreezeViews){ return; }
			setViewsState(getState());
		}
		
		protected function setViewsState(state:Object):void {
			var i:uint;
			var loopView:AbstractButtonView;
			for(i=0;i<views.length;i++){
				loopView=views[i];
				loopView.setState(state);
			}
		}
		
		private function doOver():Boolean { return true; }
		
		public function getIsPressed():Boolean{
			return isPressed;
		}
		
		public function getIsOver():Boolean{
			return isOver;
		}
		
		public function getIsEnabled():Boolean {
			return isEnabled;
		}
		
		public function setIsEnabled(bool:Boolean):void {
			bool=Boolean(bool);
			isEnabled=bool;
			if(!isEnabled){ doArtificialOut(); }
			doIsEnabled();
			updateViewers();
			broadcastEvent(event_EnabledChanged);
		}
		
		protected function getState():Object {
			if(getIsEnabled()){
				if(isPressed){
					return AbstractButtonView.state_PRESSED;
				}else if(isOver){
					return AbstractButtonView.state_OVER;
				}else{
					return AbstractButtonView.state_OUT;
				}
			}else{
				return AbstractButtonView.state_DISABLED;
			}
		}
		
		public function addButtonView(view:AbstractButtonView):void {
			if(views.indexOf(view)==-1) {
				views.push(view);
				view.setState(getState());
			}
		}
		
		/** @param buttonViews Array of AbstractButtonView */  
		public function addButtonViews(buttonViews:Array):void {
			var i:uint;
			var loopButtonView:AbstractButtonView;
			for(i=0;i<buttonViews.length;i++){
				loopButtonView=buttonViews[i];
				addButtonView(loopButtonView);
			}
		}
		
		public function getButtonViews():Array {
			return views.concat();
		}
		
		public function setPress():void {
			if(!isOver){ return; }
			if(isPressed){ return; }
			isPressed=true;
			if(getTimer()-lastPressTime<250){ broadcastEvent(event_DoublePress); }
			lastPressTime=getTimer();
			broadcastEvent(event_Press);
			updateViewers();
			ms.addEventListener(ms.event_Move, onMouseMoveWhenDown);
		}
		
		public function setRelease():void {
			if(!isOver){ return; }
			if(!isPressed){ return; }
			isPressed=false;
			broadcastEvent(event_ReleaseAll);
			broadcastEvent(event_Release);
			updateViewers();
			ms.removeEventListener(ms.event_Move, onMouseMoveWhenDown);
		}
		
		public function setReleaseOutside():void {
			if(!isPressed){ return; }
			isPressed=false;
			broadcastEvent(event_OutAndRelease);
			broadcastEvent(event_ReleaseAll);
			broadcastEvent(event_ReleaseOutside);
			updateViewers();
			ms.removeEventListener(ms.event_Move, onMouseMoveWhenDown);
		}
		
		public function setRollOut():void {
			if(!isOver){ return; }
			isOver=false;
			ms.removeListener(this);
			isDragOver=false;
			broadcastEvent(event_OutAndRelease);
			broadcastEvent(event_OverOrOut);
			broadcastEvent(event_Out);
			broadcastEvent(event_RollOut);
			updateViewers();
			ms.removeEventListener(ms.event_Move, onMouseMove);
		}
		
		public function setRollOver():void {
			if(isOver){ return; }
			if(!doOver()){ return; }
			isOver=true;
			ms.addListener(this);
			broadcastEvent(event_OverOrOut);
			broadcastEvent(event_Over);
			broadcastEvent(event_RollOver);
			updateViewers();
			ms.addEventListener(ms.event_Move, onMouseMove);
		}
		
		public function setDragOut():void {
			if(!isOver){ return; }
			isOver=false;
			ms.removeListener(this);
			isDragOver=false;
			broadcastEvent(event_OverOrOut);
			broadcastEvent(event_Out);
			broadcastEvent(event_DragOut);
			updateViewers();
			ms.removeEventListener(ms.event_Move, onMouseMove);
		}
		
		public function setDragOver():void {
			if(isOver){ return; }
			if(!doOver()){ return; }
			isDragOver=true;
			isOver=true;
			ms.addListener(this);
			broadcastEvent(event_OverOrOut);
			broadcastEvent(event_Over);
			broadcastEvent(event_DragOver);
			updateViewers();
			ms.addEventListener(ms.event_Move, onMouseMove);
		}
		
		public function getIsDragOver():Boolean {
			if(isDragOver && ms.getIsDown() && isEnabled){ 
				return true;
			}else{
				return false;
			}
		}
		
		public function doArtificialOut():void {
			if(isPressed){ setRelease(); }
			if(isOver){ setRollOut(); }
		}
		
//		private function doDelete():void {
//			doArtificialOut();
			//super.doDelete();
//		}
		
		public function gotViews():Boolean {
			return views.getLength()>0;
		}
		
		public function setIsFreezeViews(isFreezeViews:Boolean, freezeAtState:Object=null):void {
			if(this.isFreezeViews==isFreezeViews){ return; }
			if(isFreezeViews){
				if(freezeAtState){
					setViewsState(freezeAtState);
				}
				this.isFreezeViews=true;
			}else{
				this.isFreezeViews=false;
				updateViewers();
			}
		}
		
//****************************************************************************
// EVENTS for AbstractButton
//****************************************************************************
		public function onEvent(ev:MLEventInfo):void {
			switch(ev.hero){
				case ms:
					switch(ev.event) {
						case ms.event_Whell:
							broadcastEvent(event_MouseWheelWhenOver, ev.data);
						break;
					}
				break;
			}
		}
		
		protected function onMouseMove(event:Event):void {
			broadcastEvent(event_MoveWhenOver);
		}
		
		protected function onMouseMoveWhenDown(event:Event):void {
			if(!ms.getIsDown()){ ms.removeEventListener(ms.event_Move, onMouseMoveWhenDown); }
			broadcastEvent(event_MoveWhenDown);
		}
		
	}
}
